package controller;

import eccezioni.CampoErratoException;
import eccezioni.UtenteBannatoException;
import eccezioni.UtenteGiaRegistratoException;
import eccezioni.UtenteGiaVerificatoException;
import eccezioni.UtenteNonTrovatoException;
import entity.Adesione;
import entity.Annuncio;
import entity.Feedback;
import entity.IndirizzoEmail;
import entity.ModalitaPagamento;
import entity.PayPal;
import entity.UtenteRegistrato;
import java.util.LinkedList;
import java.util.UUID;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import sbForEntityClasses.FeedbackFacadeLocal;
import sbForEntityClasses.IndirizzoEmailFacadeLocal;
import sbForEntityClasses.PayPalFacadeLocal;
import sbForEntityClasses.UtenteRegistratoFacadeLocal;
import utilities.QueryBuilder;
import utilities.Regexp;

/**
 * Metodi per la registrazione dell'utente
 * @author Ale
 */
@Stateless
public class ControllerUserRegistration implements ControllerUserRegistrationLocal {

    @EJB
    private ControllerUtentiLocal controllerUtenti;
    @EJB
    private PayPalFacadeLocal payPalFacade;
    @EJB
    private FeedbackFacadeLocal feedbackFacade;
    @EJB
    private ControllerGMapsLocal controllerGMaps;
    @EJB
    private IndirizzoEmailFacadeLocal indirizzoEmailFacade;
    @EJB
    private UtenteRegistratoFacadeLocal utenteRegistratoFacade;
    @PersistenceContext(unitName = "ShippingShareBisBis-ejbPU")
    private EntityManager em;

    /**
     * Metodo per registrare un nuovo utente
     * @param mail indirizzo e-mail per la registrazione, identifica l'utente in modo univoco all'interno del sistema
     * @param password password per l'accesso, null se la registrazione è social (si veda il parametro sito)
     * @param password2 conferma della password per l'accesso, null se la registrazione è social (si veda il parametro sito)
     * @param nome nome del nuovo utente
     * @param cognome cognome del nuovo utente
     * @param indirizzo indirizzo del nuovo utente
     * @param telefono numero di telefono del nuovo utente
     * @param paypal mail dell'account paypal del nuovo utente
     * @param sito true sse la registrazione non è social (cioè è avvenuta direttamente sul sito, non utilizzando OpneId né Facebook)
     * @return il nuovo utente
     * @throws UtenteBannatoException se l'utente cerca di ri-registrarsi dopo essere stato bannato
     * @throws UtenteGiaRegistratoException se l'utente cerca di ri-registrarsi ma è già registrato
     * @throws CampoErratoException se uno o più dati forniti non sono nel formato corretto
     */
    @Override
    public UtenteRegistrato inserisciUtente(String mail, String password, String password2, String nome, String cognome, String indirizzo, String telefono, String paypal, boolean sito) throws UtenteBannatoException, UtenteGiaRegistratoException, CampoErratoException {
        //controllo errori lato server
        String errori = "";
        if (sito) {
            if (!Regexp.checkEmail(mail, true)) {
                errori += "<li>" + mail + " non &egrave; un indirizzo e-mail valido</li>";
            }
            if (!Regexp.checkPassword(password, true)) {
                errori += "<li>" + "la password deve essere compresa tra 8 e 32 caratteri</li>";
            }
            if (!Regexp.checkPasswordCoincidence(password, password2, true)) {
                errori += "<li>" + "le password non coincidono</li>";
            }
        }
        if (!controllerGMaps.isUniqueAddress(indirizzo)) {
            errori += "<li>l'indirizzo \"" + indirizzo + "\" non &egrave; stato riconosciuto</li>";
        }
        if (!Regexp.checkAlphabetic(nome, true)) {
            errori += "<li>Il nome deve essere composto solo da caratteri alfabetici</li>";
        }
        if (!Regexp.checkAlphabetic(cognome, true)) {
            errori += "<li>Il cognome deve essere composto solo da caratteri alfabetici</li>";
        }
        if (!Regexp.checkAlphanumeric(telefono, true)) {
            errori += "<li>Il telefono deve essere composto solo da caratteri alfanumerici</li>";
        }
        if (!Regexp.checkEmail(paypal, true)) {
            errori += "<li>" + paypal + " non &egrave; un indirizzo paypal valido</li>";
        }
        if (!"".equals(errori)) {
            throw new CampoErratoException(errori);
        }

        for (UtenteRegistrato u : utenteRegistratoFacade.findAll()) {
            if (u.getEmail().getIndirizzo().equals(mail) && u.isBannato()) {
                throw new UtenteBannatoException("Sei stato bannato da Shipping Share.");
            } else if (u.getEmail().getIndirizzo().equals(mail)) {
                throw new UtenteGiaRegistratoException("La tua mail risulta gi&agrave; registrata a Shipping Share.");
            }
        }

        UtenteRegistrato utente = new UtenteRegistrato();
        utente.setAdesioni(new LinkedList<Adesione>());
        utente.setAnnunciCreati(new LinkedList<Annuncio>());
        utente.setBannato(false);

        Feedback feed = new Feedback();
        feed.setFeedbackCreatore(0);
        feed.setFeedbackIscritto(0);
        feed.setNumFeedbackCreatore(0);
        feed.setNumFeedbackIscritto(0);
        feedbackFacade.create(feed);
        utente.setFeedback(feed);

        IndirizzoEmail email = new IndirizzoEmail();
        email.setIndirizzo(mail);
        indirizzoEmailFacade.create(email);
        utente.setEmail(email);

        utente.setIndirizzo(controllerUtenti.creaIndirizzo(indirizzo));

        utente.setModalitaPagamento(new LinkedList<ModalitaPagamento>());
        PayPal pp = new PayPal();
        IndirizzoEmail ppmail = new IndirizzoEmail();
        ppmail.setIndirizzo(paypal);
        indirizzoEmailFacade.create(ppmail);
        pp.setIndirizzoPostaPayPal(ppmail);
        payPalFacade.create(pp);
        utente.getModalitaPagamento().add(pp);

        utente.setNome(nome);
        utente.setCognome(cognome);
        utente.setTelefono(telefono);
        utente.setCrittoPassword(password);
        utente.setRuolo(UtenteRegistrato.Ruolo.NONVERIFICATO);
        utente.setUuid(UUID.randomUUID().toString());
        utenteRegistratoFacade.create(utente);

        return utente;
    }

    /**
     * Ricerca un utente in base all'uuid che gli viene fornito in fase di registrazione
     * @param uuid id casuale e univoco assegnato all'utente in fase di registrazione
     * @return l'utente corrispondente, se esiste
     */
    @Override
    public UtenteRegistrato findUser(String uuid) {
        QueryBuilder qb = new QueryBuilder("UtenteRegistrato", em);

        qb.addWhereEqClause("uuid", uuid);

        return ((UtenteRegistrato) qb.getQueryObject().getSingleResult());

    }

    /**
     * Verifica un utente non verificato, completandone così la registrazione
     * @param uuid l'uuid dell'utente da verificare
     * @return l'utente ora verificato
     * @throws UtenteBannatoException se l'utente cerca di ri-verificarsi dopo essere stato bannato
     * @throws UtenteNonTrovatoException se l'utente non viene trovato
     * @throws UtenteGiaVerificatoException se l'utente si ri-verifica dopo essere già stato verificato
     */
    @Override
    public UtenteRegistrato verifica(String uuid) throws UtenteBannatoException, UtenteNonTrovatoException, UtenteGiaVerificatoException {
        try {
            UtenteRegistrato ur = findUser(uuid);
            if (ur.isBannato()) {
                throw new UtenteBannatoException("Sei stato bannato da Shipping Share.");
            } else if (ur.isVerificato()) {
                throw new UtenteGiaVerificatoException("La tua registrazione era gi&agrave; completa. Puoi eseguire il login su Shipping Share");
            }
            ur.setRuolo(UtenteRegistrato.Ruolo.UTENTE);
            ur.setUuid("");
            utenteRegistratoFacade.edit(ur);

            return ur;
        } catch (NoResultException nre) {
            throw new UtenteNonTrovatoException("L'e-mail o la password inserite sono errate. Riprova!");
        }


    }

    /**
     * Modifica l'uuid dell'utente specificato con il nuovo uuid in input
     * @param uuid nuovo uuid
     * @param utente utente il cui uuid viene modificato
     */
    @Override
    public void changeUUID(String uuid, UtenteRegistrato utente) {
        utente.setUuid(uuid);
        utenteRegistratoFacade.edit(utente);
    }

    /**
     * Persistenza
     * @param object
     */
    public void persist(Object object) {
        em.persist(object);
    }
    
}
